#include <QSlider>
#include <QHBoxLayout>
#include <QHash>

#include "qtDmxSliderPanel.h"
#include "swiftslider.h"
#include "IF_lighttransitionengine.h"

/** @class QtDmxSliderPanel
 *
 * This class implements the interface ::IF_DmxSliderPanel, with a set
 * of sliders that can be manipulated to change light level and that move
 * autonomously to reveal level change produced by DMX transition engine.
 *
 * This implementation uses Qt Widgets.
 */

#define  ACTIVE_DMX_SLIDER_STYLE \
"QSlider::handle { " \
"background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #ffdd77, stop:1 #ddcc44);" \
"border: 2px solid yellow;" \
"border-radius: 4px;}"

/** a bit higher than DMX max value (255). This allows not loosing precision
 * when manually moving the slider
 */
#define  MAX_SLIDER_VALUE     300
#define  NO_INDEX_FOUND   -1  /**< value returned from QList::IndexOf */

/** transform internal steps into percent value */
#define  TICKS_TO_PERCENT( internalLevel )    ((double)internalLevel * 100. / (double)MAX_SLIDER_VALUE)
#define  PERCENT_TO_TICKS( percent)           ((int)(percent * (double)MAX_SLIDER_VALUE / 100.))


static QHash<QSlider *, int> SliderIndexMap;

/**
 * @brief The LightSlider class
 */
class LightSlider : public SwiftSlider
{
public:
   LightSlider(Qt::Orientation orientation, QWidget * parent)
      : SwiftSlider( orientation, parent) {}

protected:
   /**
    * @brief redefintion. Tooltip value is channel value in percent.
    * @param value - range [0-MAX_SLIDER_VALUE]; to be mapped to range 0% - 100%
    * @return
    */
   virtual QString formatTip(qint64 value)
   {
      return QString("%1 %").arg( (double)value*100. / (double)MAX_SLIDER_VALUE, 0, 'f', 1 );
   }
};



QtDmxSliderPanel::QtDmxSliderPanel(int numOfChannels, IF_LightTransitionEngine *transitionEngine,
                                   QWidget *parent) :
   IF_DmxSliderPanel(parent),
   m_updateInProgress(false)
{
   QHBoxLayout *layout = new QHBoxLayout( this);
   setLayout( layout );

   for (int i = 0; i < numOfChannels; i++)
   {
      LightSlider *slider = new LightSlider( Qt::Vertical, this);
      SliderIndexMap[slider] = i;
      layout->addWidget( slider);
      slider->setRange( 0, MAX_SLIDER_VALUE);

      connect( slider, SIGNAL(valueChanged(int)), this, SLOT(onSliderValueChanged(int)) );
      m_sliderSet << slider;
   }

   connect( transitionEngine, SIGNAL(fadeStep(QList<double>)),
            this, SLOT(setAllValues(QList<double>)) );
}

void QtDmxSliderPanel::setAllValues(const QList<double> &values)
{
   Q_ASSERT( values.length() == m_sliderSet.length());

   for (int i = 0; i < m_sliderSet.length(); i++)
   {
      m_updateInProgress = true;
      m_sliderSet[i]->setValue( PERCENT_TO_TICKS(values.at(i)) );
      m_updateInProgress = false;
   }
}

void QtDmxSliderPanel::setValueAtChannel(double value, int channel)
{
   Q_ASSERT( channel < m_sliderSet.length());

   m_updateInProgress = true;
   m_sliderSet[channel]->setValue( PERCENT_TO_TICKS(value) );
   m_updateInProgress = false;
}

void QtDmxSliderPanel::setDmxOn()
{
   setStyleSheet( ACTIVE_DMX_SLIDER_STYLE);
}

void QtDmxSliderPanel::setDmxOff()
{
   setStyleSheet("");
}

/**
 * called when any of the sliders is moved. This function will
 * propagate the signal with the info of which one did move.
 */
void QtDmxSliderPanel::onSliderValueChanged(int value)
{
   QSlider *sender = qobject_cast<QSlider *>(QObject::sender());

   if ((!m_updateInProgress) && (sender != NULL))
   {
      if (SliderIndexMap.contains(sender))
      {
         int senderIndex = SliderIndexMap[sender];
         double newValue = TICKS_TO_PERCENT( value );
         emit valueChangedByGUI( newValue, senderIndex );
      }
   }
}
